package cn.sunxyz.data.orm.impl;

import cn.sunxyz.data.infer.DefaultSQLFactory;
import cn.sunxyz.data.infer.SQLDialect;
import cn.sunxyz.data.infer.SQLFactory;
import cn.sunxyz.data.orm.IMethod;
import cn.sunxyz.data.orm.SQLManager;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * Created by yangrd on 2017/6/7.
 */
public class CacheSQLManager implements SQLManager {

    private static CacheSQLManager defaultSQLManager = new CacheSQLManager();

    public static CacheSQLManager getSingleton() {
        return defaultSQLManager;
    }

    private Map<String, ClassMethodSql> classMethodSqlMap = new HashMap<>();

    // 通过 className 找到 ClassMethodSql
    // 通过方法签名(methodName@入参列表) 在 ClassMethodSql 找到对应的sql
    @Override
    public String getSql(IMethod imethod) {
        Class<?> cls = imethod.getEntityClazz();
        String clsName = cls.getName();
        if (classMethodSqlMap.containsKey(clsName)) {
            return classMethodSqlMap.get(clsName).getSqlOrRegByMethod(imethod);
        } else {
            classMethodSqlMap.put(clsName, new ClassMethodSql(cls));
            return getSql(imethod);
        }
    }

    //sql查询调用

    static class ClassMethodSql {
        private static SQLFactory sqlFactory = DefaultSQLFactory.getSingleton();
        private Map<String, String> sqlMap = new HashMap<>(); //key: methodName@参数列表 => value: sql语句
        private Map<IMethod, String> methodNameMap = new HashMap<>();//key: method  => value: methodName@参数列表
        private Class<?> tClass;

        public ClassMethodSql(Class<?> tClass) {
            this.tClass = tClass;
        }

        //如果sql不存在注册
        public String getSqlOrRegByMethod(IMethod iMethod) {
            if (!methodNameMap.containsKey(iMethod)) {
                registerSqlMethod(iMethod);
            }
            return sqlMap.get(methodNameMap.get(iMethod));
        }

        private void registerSqlMethod(IMethod iMethod) {
            String name = iMethod.getName();
            Class<?>[] parameterTypes = iMethod.getParameterTypes();
            String key = name + "@";
            if (Objects.nonNull(parameterTypes)) {
                key += Arrays.asList(parameterTypes).stream().map(cls -> cls.getName()).collect(Collectors.joining(","));
            }
            methodNameMap.put(iMethod, key);
            registerSqlName(key, iMethod.getTargetClazz(), name);
        }

        private void registerSqlName(String key, Class<?> targetCls, String name) {
            registerSqlName(key, targetCls, name, SQLDialect.MY_SQL);
        }

        private void registerSqlName(String key, Class<?> targetCls, String name, SQLDialect sqlDialect) {
            if (!sqlMap.containsKey(key)) {
                String sql = null;
                try {
                    sql = sqlFactory.parser(tClass, targetCls, name, sqlDialect);//根据方法名解析出对应的sql
                } catch (Exception e) {
                    e.printStackTrace();
                }
                sqlMap.put(key, sql);
            }
        }

    }
}
